package asruby.runtime
{
import asruby.lang.RubyModule;
	
public class Frame
{
    /**
     * The class for the method we are invoking for this frame.  Note: This may not be the
     * class where the implementation of the method lives.
     */
    private var klazz: RubyModule;
    
    /**
     * The 'self' for this frame.
     */
    private var self: IRubyObject;
    
    /**
     * The name of the method being invoked in this frame.  Note: Blocks are backed by frames
     * and do not have a name.
     */
    private var name: String;

    /**
     * The block that was passed in for this frame (as either a block or a &amp;block argument).
     * The frame captures the block for super/zsuper, but also for Proc.new (with no arguments)
     * and also for block_given?.  Both of those methods needs access to the block of the 
     * previous frame to work.
     */ 
    private var block: Block;
    
    /**
     * Does this delimit a frame where an eval with binding occurred.  Used for stack traces.
     */
    private var _isBindingFrame: Boolean = false;

    /**
     * The current visibility for anything defined under this frame
     */
    private var visibility: Visibility = Visibility.PUBLIC;
    
    private var jumpTarget: JumpTarget;
    
    private var backref: IRubyObject;
    private var lastline: IRubyObject;

    public function  getJumpTarget(): JumpTarget {
        return jumpTarget;
    }

    public function  setJumpTarget(jumpTarget: JumpTarget): void {
        this.jumpTarget = jumpTarget;
    }
    
    public function  Frame() {
    }
    /**
     * The location in source where this block/method invocation is happening
     */
    
    private var fileName: String;
    private var line: int;

    public function  updateFrame(fileName: String, line: int): void {
        updateFrame3(null, null, null, Block.NULL_BLOCK, fileName, line, null); 
    }

    public function  updateFrame2(frame: Frame): void {
        //assert frame.block != null : "Block uses null object pattern.  It should NEVER be null";

        this.self = frame.self;
        this.name = frame.name;
        this.klazz = frame.klazz;
        this.fileName = frame.fileName;
        this.line = frame.line;
        this.block = frame.block;
        this.jumpTarget = frame.jumpTarget;
        this.visibility = frame.visibility;
        this._isBindingFrame = frame._isBindingFrame;
        this.backref = frame.backref;
        this.lastline = frame.lastline;
    }

    public function updateFrame3( klazz:RubyModule,  self:IRubyObject,  name:String,
                  block:Block,  fileName:String,  line:int,  jumpTarget:JumpTarget):void {
        //assert block != null : "Block uses null object pattern.  It should NEVER be null";

        this.self = self;
        this.name = name;
        this.klazz = klazz;
        this.fileName = fileName;
        this.line = line;
        this.block = block;
        this.jumpTarget = jumpTarget;
        this.visibility = Visibility.PUBLIC;
        this._isBindingFrame = false;
        this.backref = null;
        this.lastline = null;
    }

    public function updateFrame4(name: String, fileName: String, line: int): void {
        this.name = name;
        this.fileName = fileName;
        this.line = line;
    }
    
    public function  duplicate(): Frame {
        var newFrame: Frame = new Frame();
        
        newFrame.updateFrame2(this);
        
        return newFrame;
    }

    public function  getBackRef(): IRubyObject {
        return backref == null ? self.getRuntime().getNil() : backref;
    }

    public function  setBackRef(backref: IRubyObject): void {
        this.backref = backref;
    }

    public function  getLastLine(): IRubyObject {
        return lastline == null ? self.getRuntime().getNil() : lastline;
    }

    public function  setLastLine(lastline: IRubyObject): void {
        this.lastline = lastline;
    }

    public function  getFile(): String {
        return fileName;
    }
    
    public function  getLine(): int {
        return line;
    }

    public function  setFile(fileName: String): void {
        this.fileName = fileName;
    }
    
    public function  setLine(line: int): void {
        this.line = line;
    }

    /** 
     * Return class that we are supposedly calling for this invocation
     * 
     * @return the current class
     */
    public function  getKlazz(): RubyModule {
        return klazz;
    }

    /**
     * Set class that this method is supposedly calling on.  Note: This is different than
     * a native method's implementation class.
     * 
     * @param klazz the new class
     */
    public function  setKlazz(klazz: RubyModule): void {
        this.klazz = klazz;
    }

    /**
     * Set the method name associated with this frame
     * 
     * @param name the new name
     */
    public function  setName(name: String): void {
        this.name = name;
    }

    /** 
     * Get the method name associated with this frame
     * 
     * @return the method name
     */
    public function  getName(): String {
        return name;
    }

    /**
     * Get the self associated with this frame
     * 
     * @return the self
     */
    public function getSelf():IRubyObject {
        return self;
    }

    /** 
     * Set the self associated with this frame
     * 
     * @param self is the new value of self
     */
    public function  setSelf(self: IRubyObject): void {
        this.self = self;
    }
    
    /**
     * Get the visibility at the time of this frame
     * 
     * @return the visibility
     */
    public function  getVisibility(): Visibility {
        return visibility;
    }
    
    /**
     * Change the visibility associated with this frame
     * 
     * @param visibility the new visibility
     */
    public function  setVisibility(visibility: Visibility): void {
        this.visibility = visibility;
    }
    
    /**
     * Is this frame the frame which started a binding eval?
     * 
     * @return true if it is a binding frame
     */
    public function  isBindingFrame(): Boolean {
        return _isBindingFrame;
    }
    
    /**
     * Set whether this is a binding frame or not
     * 
     * @param isBindingFrame true if it is
     */
    public function  setIsBindingFrame(isBindingFrame: Boolean): void {
        this._isBindingFrame = isBindingFrame;
    }
    
    /**
     * What block is associated with this frame?
     * 
     * @return the block of this frame or NULL_BLOCK if no block given
     */
    public function  getBlock(): Block {
        return block;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public function  toString(): String {
        var sb: String = new String;
        
        sb.concat(fileName).concat(':').concat(line+1).concat(':').concat(klazz);
        if (name != null) sb.concat(" in ").concat(name);

        return sb.toString();
    }
}
}